package com.zwh.se.oop.basic;


/**
 * 这被称为测试类,其实主体就是个main方法而已,你硬写在类中也可以,但测试类专门用于测试,
 * 在面向对象设计中,描述对象的类和测试类应该分开来编写。
 * 在描述对象的类中，不需要定义main方法，专门在测试类中提供main方法。
 * PS:本汇总由于为了笔记观看方便缘故,所以并没有完全遵守这点,实际开发请务必遵守
 *
 * @author yexi
 */
public class Test {
    public static void main(String[] args) {

        System.out.println("------------------1、对象的创建----------------------------");
        //[1]类是一种数据类型.可以用于声明变量
        BasicClass basicClass;//类初始化时默认是空的,等价于 BasicClass basicClass = null
        //[2]这一瞬间其实发生了很多的事情：
        //(1):第一次试图使用类来创建对象,进行一次类的加载（只加载一次）,之后再次创建时就不会加载了
        //    (可以通过IDE的断点来进行查看,你会看到首先进入到一个loadClass方法之中)。而类的信息所加载到底地方,我们称之为"方法区"
        //(2):创建对象,在堆中开辟空间,为basicClass这个变量存储对象在堆内存中的地址空间
        //(3):对对象进行初始化操作，属性赋值都是默认的初始值。
        //(4):new关键字调用构造器，执行构造方法，在构造器中对属性重新进行赋值(new关键字本质就是调用构造方法(构造器))
        basicClass = new BasicClass();

        //合二为一的写法
        //通过new一个类出来的变量,就被称为类的一个对象,又称为类的一个实例
        //如果你现在仍然开着断点的话就会发现,在这里再次创建对象时并没有调用loadClass方法了
        BasicClass basicClass1 = new BasicClass();
        BasicClass basicClass2 = new BasicClass();
        //所定义的每个对象都是独立的且唯一的,但它们都属于同一类,都具有类中描述的特征(状态)(属性)和行为(功能)(方法)

        System.out.println("------------------2、通过对象访问类的成员----------------------------");
        //访问类的成员(.语法)
        //给对象的成员变量(字段)赋值
        basicClass.name = "kallen";
        basicClass.age = 20;

        //访问字段的值
        System.out.println(basicClass.name);
        System.out.println(basicClass.age);

        //访问方法==>通过对象调用方法
        basicClass.sayName();

        /*
         * 1>实例变量:通过对象直接调用的成员变量称为实例变量,也即实例变量必须通过实例(对象)来访问
         * 2>实例方法:通过对象直接调用的成员方法称为实例方法,也即实例方法必须通过实例(对象)来访问
         */

        System.out.println("------------------3、对象的比较----------------------------");
        BasicClass b1 = new BasicClass();
        //println(obj.toString()),输出时会调用该对象的toString()方法,所以如果想输出比较好看,就得重写toString()
        System.out.println(b1);
        // == 比较内存地址
        BasicClass b2 = new BasicClass();
        System.out.println(b1 == b2);
        // equals() 根据方法内的逻辑来进行比较(默认Object的 equals 比较的依旧是 == ),所以如果想做业务上的相同,就得重写equals()
        System.out.println(b1.equals(b2));

        System.out.println("------------------4、内存分析------------------");
        //示例一：
        BasicClass bc = new BasicClass();
        /**
         * 内存分析：
         * 1、将BasicClass.class的字节码信息加载到方法区内
         * 2、根据方法区内BasicClass这个模板在堆中开辟出内存空间（同时存储了一份字节码信息的地址指向），注意此时默认值已经有了
         * 3、通过new关键字调用了无参构造器来设置属性值，由于构造器本质上是构造方法，所以会在栈中开辟出一个BasicClass无参构造器栈帧(关键)。
         *    再由于无参构造器什么也没做，所以直接结束。将栈帧销毁(关键)。
         * 4、定义了一个main方法中的局部变量bc，因此存入到main方法的栈帧中的局部变量表，并将开辟出的内存地址值赋值给bc这个变量
         */

        //示例二：
        BasicClass bs = new BasicClass("小明", 25);
        /**
         * 内存分析：
         * 1、将BasicClass.class的字节码信息加载到方法区内（由于类的加载只会有一次，所以这个步骤实际上不会再来一次了）
         * 2、根据方法区内BasicClass这个模板在堆中开辟出内存空间（同时存储了一份字节码信息的地址指向）
         * 3、通过new关键字调用了有参构造器来设置属性值，由于构造器本质上是构造方法，所以会在栈中开辟出一个BasicClass有参构造器栈帧(关键)。
         * 4、将局部变量存到有参构造器的栈帧里面，此时，由于发现有"小明"这个字符串字面量，因此会先去查询字符串常量池看该字符串是否存在，若不存在则
         *    创建一个存储在内部，并将其处于字符串常量池中的地址返回到构造器栈帧里面。
         * 5、将栈帧里面的值一一取出，赋值给堆中的对象。将栈帧销毁(关键)。
         * 6、定义了一个main方法中的局部变量bs，因此存入到main方法的栈帧中的局部变量表，并将开辟出的内存地址值赋值给bs这个变量
         */

        //实例三：
        /**
         * @see ByValue
         * 因为东西有点多，抽出去讲，看的前提是上面两个示例已经懂了
         */


    }
}
/**
 * 面向对象三个阶段：
 * 【1】面向对象分析OOA（Object Oriented Analysis）
 * 先分析可能存在的对象：张三，王五，朱六，你，我
 * 抽取出一个类----》人类
 * <p>
 * 类里面有什么：
 * 动词--》动态特性--》方法
 * 名词--》静态特性--》属性
 * <p>
 * 【2】面向对象设计OOD（Object Oriented Design）
 * 先有类，再有对象：
 * 类：人类： Person
 * 对象：zhangsan ，lisi，zhuliu
 * <p>
 * 【3】面向对象编程OOP（Object Oriented Programming）
 */